﻿#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

//设计一个类，只能在堆上创建对象
//方案一：析构私有
// 
//class HeapOnly
//{
//public:
//    //static void Delete(HeapOnly* p)
//    //{
//    //    delete p;
//    //}
//
//    void Delete()
//    {
//        delete this;
//    }
//
//private:
//    ~HeapOnly()
//    {
//        cout << "~HeapOnly()" << endl;
//    }
//};
//
//int main()
//{
//
//    //除了动态开辟的对象，在对象生命周期结束之前都会自动调用析构
//    HeapOnly hp1;   //栈区
//    static HeapOnly hp2;    //静态区
//
//    HeapOnly* p = new HeapOnly;     //堆区
//    p->Delete();
//
//    return 0;
//}

//方案二：构造私有
//class HeapOnly
//{
//public:
//    static HeapOnly* CreateObj()
//    {
//        return new HeapOnly;
//    }
//
//    // 防拷贝
//	HeapOnly(const HeapOnly& hp) = delete;
//	HeapOnly& operator=(const HeapOnly& hp) = delete;
//
//private:
//    HeapOnly()
//    {
//        cout << "HeapOnly()" << endl;
//    }
//};
//
//int main()
//{
//    //new会自动调用构造，构造私有，无法调用
//    //HeapOnly* p = new HeapOnly;    
//    //delete p;
//
//    //调用成员函数创建对象，需要对象调用，而对象无法在类外创建，因此定义为静态成员函数
//    HeapOnly* hp = HeapOnly::CreateObj();
//    
//    //为防止类外拷贝构造（即在栈上开辟对象），禁用拷贝赋值
//    //HeapOnly hp2(*hp);
//    
//    delete hp;
//
//    return 0;
//}

//设计一个类，只能在栈上创建对象
//class StackOnly
//{
//public:
//	static StackOnly CreateObj()
//	{
//		StackOnly obj;
//		return obj;
//	}
//
//	 //不能防拷贝
//	//StackOnly(const StackOnly& st) = delete;
//	//StackOnly& operator=(const StackOnly& st) = delete;
//	void* operator new(size_t n) = delete;
//
//private:
//	StackOnly()
//		:_a(0)
//	{}
//
//private:
//	int _a;
//};
//
//int main()
//{
//	//StackOnly st1;
//	//static StackOnly st2;
//	//StackOnly* st3 = new StackOnly;
//
//	//无法防止拷贝构造，该方式创建对象也是拷贝构造
//	StackOnly st1 = StackOnly::CreateObj();
//
//	static StackOnly copy1(st1);
//
//	//通过禁用operator new来禁用动态拷贝对象
//	//StackOnly* copy2 = new StackOnly(st1);
//
//	return 0;
//}

//单例模式设计类：一个类只能创建一个对象
//饿汉模式：在进程一开始运行起来（即在main函数执行之前）就创建对象
//优点：1、简单，没有线程安全问题
//缺点：1、一个程序中，如果有多个单例，并且有先后创建初始化的需求时，饿汉模式无法控制先后
//		 （比如程序两个单例类A 和 B，假设要求A先创建初始化，B再创建初始化）
//		2、饿汉单例类，当初始化任务多的时候，会影响程序启动速度。
//class MemoryPool
//{
//public:
//	static MemoryPool* GetInstance()
//	{
//		return _pinst;
//	}
//
//	void* Alloc(size_t n)
//	{
//		void* ptr = nullptr;
//		// ....
//		return ptr;
//	}
//
//	void Dealloc(void* ptr)
//	{
//		// ...
//	}
//
//private:
//	//构造私有化
//	MemoryPool()
//	{}
//
//	char* _ptr = nullptr;
//	//...
//
//	//静态成员在类中只有一个，属于整个类所有，保住了单例模式的特点
//	//static MemoryPool _inst;	// 声明
//	static MemoryPool* _pinst;	// 两种方式都可
//};
//
////静态成员属于类中的成员变量，因此也能够调用私有构造
//MemoryPool* MemoryPool::_pinst = nullptr;


//懒汉模式：第一次使用对象时创建实例对象
// 优点：1、当有多个单例模式类时，能够控制先后创建初始化的顺序问题。
//		 2、不影响启动速度。
// 缺点：1、相对复杂。（线程安全问题）
//		 2、线程安全问题要处理好
class MemoryPool
{
public:
	static MemoryPool* GetInstance()
	{
		if (_pinst == nullptr)
		{
			_pinst = new MemoryPool;
		}

		return _pinst;
	}

	void* Alloc(size_t n)
	{
		void* ptr = nullptr;
		// ....
		return ptr;
	}

	void Dealloc(void* ptr)
	{
		// ...
	}

	// 实现一个内嵌垃圾回收类    
	class CGarbo {
	public:
		~CGarbo()
		{
			if (_pinst)
				delete _pinst;
		}
	};

private:
	//构造私有化
	MemoryPool()
	{}

	char* _ptr = nullptr;
	//...

	static MemoryPool* _pinst;	
};

MemoryPool* MemoryPool::_pinst = nullptr;

// 回收单例对象，main函数结束后，会自动调用其析构，对单例对象进行释放等工作
static MemoryPool::CGarbo gc;	

// 单例对象释放问题：
// 1、一般情况下，单例对象不需要释放的。因为一般整个程序运行期间都可能会使用它。
//	  单例对象在进程正常结束后，也会自动释放资源。
// 2、有些特殊场景需要释放，比如单例对象析构，要进行一些持久化(往文件、数据库写)操作时
//	  可以实现一个内嵌垃圾回收类，定义一个静态对象，在进程正常结束后，会自动调用其析构对单例对象的持久化做处理操作

int main()
{
	//单例模式保证无法自己创建对象
	//MemoryPool mp1;
	//MemoryPool mp2;

	//单例模式的大概使用方式
	void* ptr1 = MemoryPool::GetInstance()->Alloc(100);
	MemoryPool::GetInstance()->Dealloc(ptr1);

	return 0;
}